﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICSharpCode.TextEditor.Document;
using System.Xml;
using System.Collections;
using System.IO;

namespace Ricciolo.StylesExplorer.Components
{
    public class XmlFoldingStrategy : IFoldingStrategy
    {
        // Fields
        private bool showAttributesWhenFolded;

        // Methods
        private void CreateCommentFold(IDocument document, List<FoldMarker> foldMarkers, XmlTextReader reader)
        {
            if (reader.Value != null)
            {
                string[] strArray = reader.Value.Replace("\r\n", "\n").Split(new char[] { '\n' });
                if (strArray.Length > 1)
                {
                    int startColumn = reader.LinePosition - 5;
                    int startLine = reader.LineNumber - 1;
                    int endColumn = (strArray[strArray.Length - 1].Length + startColumn) + 3;
                    int endLine = (startLine + strArray.Length) - 1;
                    string foldText = "<!--" + strArray[0] + "-->";
                    FoldMarker item = new FoldMarker(document, startLine, startColumn, endLine, endColumn, FoldType.TypeBody, foldText);
                    foldMarkers.Add(item);
                }
            }
        }

        private void CreateElementFold(IDocument document, List<FoldMarker> foldMarkers, XmlTextReader reader, XmlFoldStart foldStart)
        {
            int endLine = reader.LineNumber - 1;
            if (endLine > foldStart.Line)
            {
                int endColumn = reader.LinePosition + foldStart.Name.Length;
                FoldMarker item = new FoldMarker(document, foldStart.Line, foldStart.Column, endLine, endColumn, FoldType.TypeBody, foldStart.FoldText);
                foldMarkers.Add(item);
            }
        }

        private XmlFoldStart CreateElementFoldStart(XmlTextReader reader)
        {
            XmlFoldStart start = new XmlFoldStart(reader.Prefix, reader.LocalName, reader.LineNumber - 1, reader.LinePosition - 2);
            if (this.showAttributesWhenFolded && reader.HasAttributes)
            {
                start.FoldText = "<" + start.Name + " " + this.GetAttributeFoldText(reader) + ">";
                return start;
            }
            start.FoldText = "<" + start.Name + ">";
            return start;
        }

        public List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation)
        {
            this.showAttributesWhenFolded = true;
            List<FoldMarker> foldMarkers = new List<FoldMarker>();
            Stack stack = new Stack();
            try
            {
                XmlTextReader reader = new XmlTextReader(new StringReader(document.TextContent));
                while (reader.Read())
                {
                    XmlFoldStart start2;
                    XmlNodeType nodeType = reader.NodeType;
                    if (nodeType != XmlNodeType.Element)
                    {
                        if (nodeType == XmlNodeType.Comment)
                        {
                            goto Label_0077;
                        }
                        if (nodeType == XmlNodeType.EndElement)
                        {
                            goto Label_005D;
                        }
                    }
                    else if (!reader.IsEmptyElement)
                    {
                        XmlFoldStart start = this.CreateElementFoldStart(reader);
                        stack.Push(start);
                    }
                    continue;
                Label_005D:
                    start2 = (XmlFoldStart)stack.Pop();
                    this.CreateElementFold(document, foldMarkers, reader, start2);
                    continue;
                Label_0077:
                    this.CreateCommentFold(document, foldMarkers, reader);
                }
            }
            catch (Exception)
            {
                List<FoldMarker> list2 = new List<FoldMarker>();
                foreach (FoldMarker marker in document.FoldingManager.FoldMarker)
                {
                    list2.Add(marker);
                }
                return list2;
            }
            return foldMarkers;
        }

        private string GetAttributeFoldText(XmlTextReader reader)
        {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < reader.AttributeCount; i++)
            {
                reader.MoveToAttribute(i);
                builder.Append(reader.Name);
                builder.Append("=");
                builder.Append(reader.QuoteChar.ToString());
                builder.Append(XmlEncodeAttributeValue(reader.Value, reader.QuoteChar));
                builder.Append(reader.QuoteChar.ToString());
                if (i < (reader.AttributeCount - 1))
                {
                    builder.Append(" ");
                }
            }
            return builder.ToString();
        }

        private static string XmlEncodeAttributeValue(string attributeValue, char quoteChar)
        {
            StringBuilder builder = new StringBuilder(attributeValue);
            builder.Replace("&", "&amp;");
            builder.Replace("<", "&lt;");
            builder.Replace(">", "&gt;");
            if (quoteChar == '"')
            {
                builder.Replace("\"", "&quot;");
            }
            else
            {
                builder.Replace("'", "&apos;");
            }
            return builder.ToString();
        }
    }

    public class XmlFoldStart
    {
        // Fields
        private int col;
        private string foldText = string.Empty;
        private int line;
        private string name = string.Empty;
        private string prefix = string.Empty;

        // Methods
        public XmlFoldStart(string prefix, string name, int line, int col)
        {
            this.line = line;
            this.col = col;
            this.prefix = prefix;
            this.name = name;
        }

        // Properties
        public int Column
        {
            get
            {
                return this.col;
            }
        }

        public string FoldText
        {
            get
            {
                return this.foldText;
            }
            set
            {
                this.foldText = value;
            }
        }

        public int Line
        {
            get
            {
                return this.line;
            }
        }

        public string Name
        {
            get
            {
                if (this.prefix.Length > 0)
                {
                    return (this.prefix + ":" + this.name);
                }
                return this.name;
            }
        }
    }

}
